#include <errno.h>
#include <myFs/adaptor.h>
#include <spdlog/spdlog.h>
#include <sys/time.h>
#include <time.h>
#include <cassert>
#include <shared_mutex>

namespace adaptor {
namespace fuse {
using namespace spdlog;
using FS = Adaptor::FS;

Adaptor::Adaptor(FS *pFS) { m_pFS = pFS; };
Adaptor &Adaptor::init(FS &FS) {
    static Adaptor adaptor(&FS);
    return adaptor;
}
FS &Adaptor::myFS() { return *m_pFS; }

int Adaptor::getattr(const char *path, struct stat *st, struct fuse_file_info *fi) {
    info("{}: path = {}", __func__, std::string(path));
    memset(st, 0, sizeof(struct stat));
    myFs::basic::Inode inode;
    size_t             ret;
    {
        std::shared_lock<std::shared_mutex> lock(s_mtx);
        ret = myFS().getattr(std::string(path), inode);
    }
    if (ret == -1) return -ENOENT;
    st->st_atim  = inode.atim;
    st->st_ctim  = inode.ctim;
    st->st_mtim  = inode.mtim;
    st->st_mode  = inode.mode;
    st->st_uid   = inode.uid;
    st->st_gid   = inode.gid;
    st->st_nlink = inode.nlink;
    st->st_size  = inode.size;
    debug("{}: ret = {}", __func__, ret);
    return ret;
}
int Adaptor::mknod(const char *path, mode_t mode, dev_t) {
    info("mknod path = {}", std::string(path));
    std::unique_lock<std::shared_mutex> lock(s_mtx);
    return myFS().mknod(std::string(path));
}
int Adaptor::mkdir(const char *path, mode_t mode) {
    info("mkdir path = {}", std::string(path));
    std::unique_lock<std::shared_mutex> lock(s_mtx);
    return myFS().mkdir(std::string(path));
}
int Adaptor::rmdir(const char *path) {
    info("rmdir path = {}", std::string(path));
    std::unique_lock<std::shared_mutex> lock(s_mtx);
    return myFS().rmdir(std::string(path));
}
int Adaptor::rename(const char *path1, const char *path2, unsigned int flags) {
    info("rename path1 = {}, path3 = {}", std::string(path1), std::string(path2));
    std::unique_lock<std::shared_mutex> lock(s_mtx);
    return myFS().rename(std::string(path1), std::string(path2));
}
int Adaptor::read(const char *path, char *buf, std::size_t size, off_t off, struct fuse_file_info *) {
    info("read path = {}", std::string(path));
    std::shared_lock<std::shared_mutex> lock(s_mtx);
    return myFS().read(std::string(path), buf, size, off);
}
int Adaptor::write(const char *path, const char *data, std::size_t size, off_t off, struct fuse_file_info *) {
    info("write path = {}", std::string(path));
    std::unique_lock<std::shared_mutex> lock(s_mtx);
    return myFS().write(std::string(path), data, size, off);
}
int Adaptor::statfs(const char *, struct statvfs *) { return 0; }
int Adaptor::readdir(
    const char *path, void *buf, fuse_fill_dir_t filler, off_t, struct fuse_file_info *, enum fuse_readdir_flags) {
    info("readdir path = {}", std::string(path));
    enum fuse_fill_dir_flags             zero {};
    std::vector<::myFs::basic::DirEntry> dir;
    {
        std::shared_lock<std::shared_mutex> lock(s_mtx);
        myFS().readdir(std::string(path), dir);
    }
    for (auto &[name, inum] : dir) {
        spdlog::info("dir name = {}", name);
        filler(buf, name, NULL, 0, zero);
    }
    return 0;
}
int Adaptor::open(const char *path, struct fuse_file_info *fi) {
    info("open path = {}", std::string(path));
    std::shared_lock<std::shared_mutex> lock(s_mtx);
    return myFS().open(std::string(path));
}
int Adaptor::unlink(const char *path) {
    info("unlink path = {}", std::string(path));
    std::unique_lock<std::shared_mutex> lock(s_mtx);
    return myFS().unlink(std::string(path));
}
int Adaptor::releasedir(const char *path, struct fuse_file_info *fi) {
    info("releasedir path = {}", std::string(path));
    std::unique_lock<std::shared_mutex> lock(s_mtx);
    return myFS().releasedir(std::string(path));
}
}  // namespace fuse
}  // namespace adaptor
